package com.gbiac.modules.monitor.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gbiac.modules.monitor.constant.MonitorConstant;
import com.gbiac.modules.monitor.entity.Rule;
import com.gbiac.modules.monitor.entity.SeatGroup;
import com.gbiac.modules.monitor.entity.Violation;
import com.gbiac.modules.monitor.entity.ViolationNotice;
import com.gbiac.modules.monitor.event.AiDeviceOpenCameraTaskEvent;
import com.gbiac.modules.monitor.http.HttpApi;
import com.gbiac.modules.monitor.model.dto.*;
import com.gbiac.modules.monitor.model.form.AiWarnMessageForm;
import com.gbiac.modules.monitor.service.*;
import com.gbiac.modules.monitor.util.DozerUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @Description: AI设备接口对接服务
 * @Author: fengchengguo
 * @Date:   2024-11-30
 * @Version: V1.0
 */
@Service
@Slf4j
public class AiDeviceServiceImpl implements AiDeviceService {

    @Resource
    private HttpApi httpApi;
    @Resource
    private ISeatFaceLoginService iSeatFaceLoginService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private IViolationNoticeService iViolationNoticeService;
    @Resource
    private IViolationService iViolationService;
    @Resource
    private ISeatGroupService iSeatGroupService;
    @Resource
    @Lazy
    private ISysBaseAPI iSysBaseAPI;
    @Value(value = "${jeecg.path.upload}")
    private String uploadpath;
    @Resource
    private IRuleService ruleService;
    @Resource
    private ApplicationContext applicationContext;

    @Resource
    private ISeatUserService iSeatUserService;


    @Override
    public void addAiWarnMessage(AiWarnMessageForm aiWarnMessageForm) {
        log.info("===addAiWarnMessage入参:{}", JSON.toJSONString(aiWarnMessageForm));

        //校验规则
        Boolean rule = checkRule(aiWarnMessageForm);
        //不符合规则，则返回
        if(!rule){
           return;
        }

        String cameraCode = aiWarnMessageForm.getCamera_code();
        String json = (String) redisUtil.get(MonitorConstant.REDIS_AI_PREFIX + ":" + cameraCode);
        JSONObject jsonObject = JSON.parseObject(json);
        String userId = jsonObject.getString("userId");
        ViolationNotice notice = iViolationNoticeService.queryUserViolationNotice(userId,aiWarnMessageForm.getWarning_type(), DateUtils.formatDate("yyyy-MM-dd"));
        Integer noticeCount = 1;
        if(notice != null){
            ViolationNotice newViolationNotice = new ViolationNotice();
            BeanUtils.copyProperties(notice, newViolationNotice, "id, createBy, createTime, updateBy, updateTime");
            noticeCount = notice.getNoticeCount()+1;
            newViolationNotice.setNoticeCount(noticeCount);
            newViolationNotice.setId(null);
            newViolationNotice.setViolationTime(aiWarnMessageForm.getCreated_time());
            newViolationNotice.setCreateTime(new Date());
            newViolationNotice.setUpdateTime(new Date());
            iViolationNoticeService.save(newViolationNotice);
        }else {
            notice = saveViolationNotice(aiWarnMessageForm,userId);
            noticeCount= 1;

        };
        int ruleSetNum = getRuleSetNum(aiWarnMessageForm.getWarning_type());
        if(noticeCount>ruleSetNum){
            Violation violation = DozerUtils.convert(notice, Violation.class);
            violation.setId(null);
            iViolationService.save(violation);
        }


    }

    @Override
    public Boolean openAiDevice(String cameraCode) {
        try {
            log.info("===openAiDevice入参:{}", cameraCode);
            AiDeviceSwitchParamDTO aiSwitchDTO = new AiDeviceSwitchParamDTO(cameraCode, 1);
            log.info("===openAiDevice入参:{}", JSONObject.toJSONString(aiSwitchDTO));
            AiDeviceSwitchResponseDTO response = httpApi.postOpenOrCloseAiDevice(JSONObject.toJSON(aiSwitchDTO));
            return response.getSuccess();
        }catch (Exception e){
            log.error("===openAiDevice异常",e.getMessage());
            return false;
        }
    }

//    @Override
//    public Boolean closeAiDevice(String cameraCode) {
//        try{
//            log.info("===closeAiDevice入参:{}", cameraCode);
//            AiDeviceSwitchParamDTO aiSwitchDTO = new AiDeviceSwitchParamDTO(cameraCode, 0);
//            log.info("===postOpenAiDevice入参:{}", JSONObject.toJSONString(aiSwitchDTO));
//            AiDeviceSwitchResponseDTO response = httpApi.postOpenOrCloseAiDevice(aiSwitchDTO);
//            return response.getSuccess();
//        }catch (Exception e){
//            log.error("===closeAiDevice异常",e);
//            return false;
//        }
//    }

    @Override
    public Object callbackAFR(AIDeviceCallbackAFRParamDTO aiDeviceCallbackAFRParamDTO) {
        log.info("===callbackAFR入参:{}", JSON.toJSONString(aiDeviceCallbackAFRParamDTO));
        Integer result = 1;
        try {
            String cameraCode = aiDeviceCallbackAFRParamDTO.getCamera_code();
            String position = aiDeviceCallbackAFRParamDTO.getPosition();
            String userId = aiDeviceCallbackAFRParamDTO.getWarning_value();
            boolean b = iSeatFaceLoginService.loginCallback(position, userId);
            if (b) {
                AiDeviceCameraRelationDTO aiDeviceCameraRelationDTO = new AiDeviceCameraRelationDTO();
                aiDeviceCameraRelationDTO.setCameraCode(cameraCode);
                aiDeviceCameraRelationDTO.setUserId(userId);
                aiDeviceCameraRelationDTO.setSeatId(position);
                redisUtil.set(MonitorConstant.REDIS_AI_PREFIX+":"+cameraCode,JSONObject.toJSONString(aiDeviceCameraRelationDTO));
                applicationContext.publishEvent(new AiDeviceOpenCameraTaskEvent(aiDeviceCameraRelationDTO,5));
            }
        }catch (Exception e){
            log.error("===callbackAFR异常", e);
        }
        return JSON.toJSON(new AiDeviceCallbackAFRResponseDTO(result));
    }

    public Boolean openCameraTask(AiDeviceCameraRelationDTO aiDeviceCameraRelationDTO) {
        AiDeviceGetTaskCodeResponseDTO aiDeviceGetTaskCodeResponseDTO = httpApi.postGetTaskCodeAiDevice(aiDeviceCameraRelationDTO.getCameraCode(),"行为检测算法");
        AiDeviceSwitchTaskParamDTO aiDeviceSwitchTaskParamDTO = null;
        log.info("===aiDeviceGetTaskCodeResponseDTO:{}",JSONObject.toJSONString(aiDeviceGetTaskCodeResponseDTO));
        if(aiDeviceGetTaskCodeResponseDTO.getSuccess()){
            List<AiDeviceGetTaskCodeResponseDTO.DataDTO> data = aiDeviceGetTaskCodeResponseDTO.getData();
            if(CollectionUtil.isNotEmpty(data)){
                AiDeviceGetTaskCodeResponseDTO.DataDTO dataDTO = data.get(0);
                String code = dataDTO.getCode();
                log.info("===code:{}",code);
                if(StringUtils.isNotEmpty(code)) {
                    aiDeviceSwitchTaskParamDTO = new AiDeviceSwitchTaskParamDTO(code,1);
                    AiDeviceSwitchTaskResponseDTO aiDeviceSwitchTaskResponseDTO = httpApi.postSwitchTaskAiDevice(JSON.toJSON(aiDeviceSwitchTaskParamDTO));
                    if(aiDeviceSwitchTaskResponseDTO.getSuccess()){
                        //开启成功后存入任务code，用于关闭摄像头行为检测
                        aiDeviceCameraRelationDTO.setTaskCode(code);
                        redisUtil.set(MonitorConstant.REDIS_AI_PREFIX+":"+aiDeviceCameraRelationDTO.getCameraCode(),JSONObject.toJSONString(aiDeviceCameraRelationDTO));
                        return true;
                    }
                }
            }
        }
        log.info("===打开行为检测监控失败:{},{}",JSONObject.toJSONString(aiDeviceGetTaskCodeResponseDTO),JSONObject.toJSONString(aiDeviceSwitchTaskParamDTO));
        return false;
    }

    @Override
    public Boolean closeCameraTask(String cameraCode) {
        String key = MonitorConstant.REDIS_AI_PREFIX + ":" + cameraCode;
        String json = (String) redisUtil.get(key);
        if(StringUtils.isNotEmpty(json)){
            AiDeviceSwitchTaskParamDTO aiDeviceSwitchTaskParamDTO = JSONObject.parseObject(json, AiDeviceSwitchTaskParamDTO.class);
            String taskCode = aiDeviceSwitchTaskParamDTO.getTaskCode();
            if(StringUtils.isNotEmpty(taskCode)){
                aiDeviceSwitchTaskParamDTO = new AiDeviceSwitchTaskParamDTO(cameraCode,0);
                AiDeviceSwitchTaskResponseDTO aiDeviceSwitchTaskResponseDTO = httpApi.postSwitchTaskAiDevice(JSON.toJSON(aiDeviceSwitchTaskParamDTO));
                if(aiDeviceSwitchTaskResponseDTO.getSuccess()){
                    //开启成功后存入任务code，用于关闭摄像头行为检测
                    aiDeviceSwitchTaskParamDTO.setTaskCode(null);
                    redisUtil.set(MonitorConstant.REDIS_AI_PREFIX+":"+cameraCode,JSONObject.toJSONString(aiDeviceSwitchTaskParamDTO));
                }
                return aiDeviceSwitchTaskResponseDTO.getSuccess();
            }
        }
        return true;
    }

    @Override
    public Result<String> addPersonAIDevice(LoginUser loginUser) {
        String jsonText = (String) redisUtil.get(MonitorConstant.REDIS_AI_PREFIX_SYNCED_USERS);
        if(jsonText == null){
            jsonText = "{}";
        }
        JSONObject json = JSONObject.parseObject(jsonText);
        String id = loginUser.getId();
        String value = json.getString(id);
        if(StringUtils.isNotBlank(value)){
            return Result.error("人员已经同步");
        }

        String avatar = loginUser.getAvatar();
        if(StringUtils.isEmpty(avatar)){
            return Result.error("同步失败，人员头像为空");
        }

        String filePath = uploadpath + File.separator + avatar;
        File file = new File(filePath);
        AiDeviceAddStaffResponseDTO aiDeviceAddStaffResponseDTO = httpApi.postAddStaffAiDevice(file, id);
        if(aiDeviceAddStaffResponseDTO.getSuccess()){
            json.put(id,id);
            redisUtil.set(MonitorConstant.REDIS_AI_PREFIX_SYNCED_USERS,json.toJSONString());
            return Result.ok();
        }else {
            return Result.error(aiDeviceAddStaffResponseDTO.getDetail());
        }
    }

    @Override
    public Result<String> deletePersonAIDevice(String id) {
        AiDeviceDeleteStaffResponseDTO aiDeviceDeleteStaffResponseDTO = httpApi.postDeleteStaffAiDevice(new AiDeviceDeleteStaffParamDTO(id));
        if(aiDeviceDeleteStaffResponseDTO.getSuccess()){
            return Result.ok();
        }else {
            return Result.error(aiDeviceDeleteStaffResponseDTO.getDetail());
        }
    }

    @Override
    public Result<String> batchAddPersonAIDevice(List<LoginUser> loginUserList) {
        StringBuffer buffer = new StringBuffer();

        for (int i = 0; i < loginUserList.size(); i++) {
            LoginUser sysUser = loginUserList.get(i);
            try {
                Result<String> result1 = addPersonAIDevice(sysUser);
                buffer.append("添加(id=").append(sysUser.getId()).append(")结果为:(").append(result1.getMessage()).append(")\n");
            }catch (Exception e){
                log.error(e.getMessage(),e);
                buffer.append("添加(id=").append(sysUser.getId()).append(")异常:(").append(e.getMessage()).append(")\n");
            }
        }
        return Result.ok(buffer.toString());
    }


    public Boolean checkRule(AiWarnMessageForm aiWarnMessageForm) {
        //校验宽松时间,在宽松时间内，则返回true
        Boolean result = checkFreeTime(aiWarnMessageForm);
        //如果符合规则，则返回true
        if(result){
            return true;
        }

        //不符合宽松时间规则，则继续
        //获取该人员首次违规记录时间
        String cameraCode = aiWarnMessageForm.getCamera_code();
        String jsonText = (String) redisUtil.get(MonitorConstant.REDIS_AI_PREFIX + ":" + cameraCode);

        JSONObject json = JSON.parseObject(jsonText);
        String userId = json.getString("userId");

        Long preTime = (Long) redisUtil.get(MonitorConstant.REDIS_AI_PREFIX_RULE_USERS + ":" + userId + ":" + aiWarnMessageForm.getWarning_type());
        if(preTime != null){
            log.info("===首次时间：{}：",DateUtils.formatDate(new Date(preTime),"yyyy-MM-dd HH:mm:ss"));
        }
        Long thisTime = aiWarnMessageForm.getCreated_time().getTime();
        log.info("===本次时间：{}：",DateUtils.formatDate(new Date(thisTime),"yyyy-MM-dd HH:mm:ss"));
        //如果没有首次违规记录时间，则记录首次违规时间，并返回false
        if(preTime == null){
            redisUtil.set(MonitorConstant.REDIS_AI_PREFIX_RULE_USERS + ":" + userId + ":" + aiWarnMessageForm.getWarning_type(),thisTime);
            return false;
        }else {//如果有首次违规记录时间，则取出记录首次违规时间与本次违规时间相减，如果结果大于规则配置中的分钟，则返回true，否则返回false
            long l = thisTime.longValue() - preTime.longValue();
            long l1 = l / 1000 / 60;
            System.out.println(l1);
            int minute = getRuleSetMinute(aiWarnMessageForm);
            if(l1 > (minute+3)){//如果本次相差时间大于（设置的分钟+3）分钟，3分钟为允许误差的时间，则保存当前时间作为重新开始计时的时间
                redisUtil.set(MonitorConstant.REDIS_AI_PREFIX_RULE_USERS + ":" + userId + ":" + aiWarnMessageForm.getWarning_type(),thisTime);
                return false;
            }

            if(minute != 0 && l1 >= minute){//重新计时
                redisUtil.set(MonitorConstant.REDIS_AI_PREFIX_RULE_USERS + ":" + userId + ":" + aiWarnMessageForm.getWarning_type(),thisTime);
                return true;
            }
            return false;
        }


    }

    private Boolean checkFreeTime(AiWarnMessageForm aiWarnMessageForm) {

        String startVal = getRuleSetVal(Rule.Key.ViolationRule.OnlyNotice.START_TIME);
        String[] startTime = startVal.split(":");
        Calendar startC = Calendar.getInstance();
        startC.set(Calendar.HOUR_OF_DAY,Integer.parseInt(startTime[0]));
        startC.set(Calendar.MINUTE,Integer.parseInt(startTime[1]));

        String endVal = getRuleSetVal(Rule.Key.ViolationRule.OnlyNotice.END_TIME);
        String[] endTime = endVal.split(":");
        Calendar endTimeC = Calendar.getInstance();
        endTimeC.set(Calendar.HOUR_OF_DAY,Integer.parseInt(endTime[0]));
        endTimeC.set(Calendar.MINUTE,Integer.parseInt(endTime[1]));


        long time = aiWarnMessageForm.getCreated_time().getTime();
        long sTime = startC.getTime().getTime();
        long eTime = endTimeC.getTime().getTime();
        log.info("===校验宽松时间，传入时间time{},开始时间：{},结束时间:{}",DateUtils.formatDate(new Date(time),"yyyy-MM-dd HH:mm:ss"),DateUtils.formatDate(startC.getTime(),"yyyy-MM-dd HH:mm:ss"),DateUtils.formatDate(endTimeC.getTime(),"yyyy-MM-dd HH:mm:ss"));
        //在宽松时间内
        if(time >= sTime && time <= eTime){
            return true;
        }
        return false;
    }

    private String getRuleSetVal(String ruleKey){
        //获取规则
        String val = (String) redisUtil.get(MonitorConstant.REDIS_AI_PREFIX_RULE_SETS+":"+ruleKey);
        if(StringUtils.isEmpty(val)){
            val = ruleService.getRuleVal(ruleKey);
            redisUtil.set(MonitorConstant.REDIS_AI_PREFIX_RULE_SETS+":"+ruleKey, val);
        }
        return val;
    }

    private int getRuleSetMinute(AiWarnMessageForm aiWarnMessageForm) {
        String warningType = aiWarnMessageForm.getWarning_type();
        String seatId = aiWarnMessageForm.getPosition();
        //根据类型返回相应的规则配置值
        if(MonitorConstant.REDIS_AI_PREFIX_WARN_TYPE_SLEEP.equals(warningType)){
            String val = getRuleSetVal(Rule.Key.ViolationRule.Sleep.TIME);
            return Integer.valueOf(val);
        }else if(MonitorConstant.REDIS_AI_PREFIX_WARN_TYPE_LEAVED.equals(warningType)){
            boolean checkOutTemp = iSeatUserService.isCheckOutTemp(seatId);
            String val;
            if(checkOutTemp) {
                val = getRuleSetVal(Rule.Key.ViolationRule.LeaveTemp.TIME);
            }else {
                val = getRuleSetVal(Rule.Key.ViolationRule.LeaveTempNo.TIME);
            }
            return Integer.valueOf(val);
        }else {
            //玩手机设置为3分钟
            return 3;
        }
    }


    /**
     * 获取次数
     * @param warningType
     * @return
     */
    private int getRuleSetNum(String warningType) {
        //根据类型返回相应的规则配置值
        if(MonitorConstant.REDIS_AI_PREFIX_WARN_TYPE_SLEEP.equals(warningType)){
            String val = getRuleSetVal(Rule.Key.ViolationRule.Sleep.NOTICE_NUM);
            return Integer.valueOf(val);
        }else if(MonitorConstant.REDIS_AI_PREFIX_WARN_TYPE_LEAVED.equals(warningType)){
            String  val = getRuleSetVal(Rule.Key.ViolationRule.LeaveTempNo.NOTICE_NUM);
            return Integer.valueOf(val);
        }else {
            //玩手机
            String  val = getRuleSetVal(Rule.Key.ViolationRule.Phone.NOTICE_NUM);
            return Integer.valueOf(val);
        }
    }

    public static void main(String[] args) {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY,Integer.parseInt("03"));
        c.set(Calendar.MINUTE,Integer.parseInt("04"));
        System.out.println(DateUtils.formatDate(c.getTime(),"yyyy-MM-dd HH:mm:ss"));
        System.out.println(c.getTime().getTime());


        Calendar c1 = Calendar.getInstance();
        c1.set(Calendar.HOUR_OF_DAY,Integer.parseInt("03"));
        c1.set(Calendar.MINUTE,Integer.parseInt("05"));

        System.out.println(DateUtils.formatDate(c1.getTime(),"yyyy-MM-dd HH:mm:ss"));
        System.out.println(c1.getTime().getTime());

        c1 = Calendar.getInstance();
        c1.set(Calendar.HOUR_OF_DAY,Integer.parseInt("03"));
        c1.set(Calendar.MINUTE,Integer.parseInt("07"));
        System.out.println(DateUtils.formatDate(c1.getTime(),"yyyy-MM-dd HH:mm:ss"));
        System.out.println(c1.getTime().getTime());

        c1 = Calendar.getInstance();
        c1.set(Calendar.HOUR_OF_DAY,Integer.parseInt("03"));
        c1.set(Calendar.MINUTE,Integer.parseInt("09"));
        System.out.println(DateUtils.formatDate(c1.getTime(),"yyyy-MM-dd HH:mm:ss"));
        System.out.println(c1.getTime().getTime());
    }




    private ViolationNotice saveViolationNotice(AiWarnMessageForm aiWarnMessageForm,String userId) {
        LoginUser user = iSysBaseAPI.getUserById(userId);
        SeatGroup group = iSeatGroupService.queryGroupBySeatId(aiWarnMessageForm.getPosition());
        ViolationNotice violationNotice = new ViolationNotice();
        violationNotice.setCreateBy("0");
        violationNotice.setCreateTime(new Date());
        violationNotice.setUpdateBy("0");
        violationNotice.setUpdateTime(new Date());
        violationNotice.setDelFlag(MonitorConstant.CONSTANT_NO_DEL_FLAG);
        violationNotice.setViolationType(aiWarnMessageForm.getWarning_type());
        violationNotice.setGroupViolation(MonitorConstant.CONSTANT_NO_GROUP_VIOLATION);
        violationNotice.setGroupName(group!=null?group.getGroupName():null);
        violationNotice.setNoticeCount(1);
        violationNotice.setUserId(userId);
        violationNotice.setUsername(user.getUsername());
        violationNotice.setRealname(user.getRealname());
        violationNotice.setPhone(user.getPhone());
        violationNotice.setUserType(user.getUserType());
        violationNotice.setSeatId(aiWarnMessageForm.getPosition());
        violationNotice.setViolationTime(aiWarnMessageForm.getCreated_time());
        if(CollectionUtil.isNotEmpty(user.getRoleList())) {
            violationNotice.setRoleName(user.getRoleList().get(0).getRoleName());
            violationNotice.setRoleCode(user.getRoleList().get(0).getRoleCode());
        }
        violationNotice.setSysOrgCode(user.getOrgCode());
        violationNotice.setOrgCode(user.getOrgCode());
        iViolationNoticeService.save(violationNotice);
        return violationNotice;
    }
}
